use std::fmt;
use std::ops;

#[derive(Debug, Eq)]
pub struct Fraction {
    num: usize,
    den: usize,
}

impl Fraction {
    pub fn new(num: usize, den: usize) -> Fraction {
        Fraction { num, den }
    }
    pub fn reduce(&self) -> Fraction {
        let (mut a, mut b) = if self.num > self.den {
            (self.num, self.den)
        } else {
            (self.den, self.num)
        };
        while a % b != 0 {
            let c = a % b;
            a = b;
            b = c;
        }
        Fraction {
            num: self.num / b,
            den: self.den / b,
        }
    }
    pub fn unpack(&self) -> (usize, usize) {
        (self.num, self.den)
    }
    pub fn is_non_trivial(&self) -> bool {
        if 9 < self.num && self.num < self.den && self.den < 100 {
            let (a, b) = (self.num / 10, self.num % 10);
            let (c, d) = (self.den / 10, self.den % 10);
            if a == d {
                if self.num * c == self.den * b {
                    return true;
                }
            } else if b == c {
                if self.num * d == self.den * a {
                    return true;
                }
            }
        }
        false
    }
}

impl fmt::Display for Fraction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} / {}", self.num, self.den)
    }
}

impl PartialEq for Fraction {
    fn eq(&self, other: &Self) -> bool {
        self.num * other.den == self.den * other.num
    }
}

impl ops::MulAssign for Fraction {
    fn mul_assign(&mut self, other: Fraction) {
        self.num *= other.num;
        self.den *= other.den;
    }
}
